﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using Xunit;

namespace UniSender.Test
{
    public class TestImportArgs
    {
        ImportConfig import;
        IDictionary<string, object> args;

        DateTime
            firstTime = new DateTime(2014, 7, 15, 10, 30, 5, DateTimeKind.Utc),
            secondTime = new DateTime(2014, 7, 15, 10, 30, 5);

        public TestImportArgs()
        {
            import = new ImportConfig(
                new ImportSubscriber()
                {
                    Email = new EmailContact("first@mail.ru")
                    {
                        Status = ContactStatus.New,
                        Availability = ContactAvailability.Available,
                        AddTime = firstTime,
                        RequestIP = "123.123.123.123",
                        ConfirmTime = firstTime,
                        ConfirmIP = "123.123.123.123",
                        Subscriptions = new Subscription[]
                        {
                            new Subscription(1, firstTime),
                            new Subscription(2, firstTime)
                        }
                    },
                    Custom = new Dictionary<string, string>()
                    {
                        { "Name", "Mr. First" },
                        { "Company", "The First" }
                    },
                    Tags = new string[] { "import", "new" }
                },
                new ImportSubscriber()
                {
                    Phone = new PhoneContact("79021234567")
                    {
                        Status = ContactStatus.Active,
                        Availability = ContactAvailability.Available,
                        AddTime = secondTime,
                        RequestIP = "124.124.124.124",
                        Subscriptions = new Subscription[]
                        {
                            new Subscription(1, secondTime)
                        },
                        ExcludedListIds = new long[] { 2, 3 },
                        UnsubscribedListIds = new long[] { 10 }
                    },
                    Custom = new Dictionary<string, string>()
                    {
                        { "Name", "Mr. Second" },
                        { "Company", "The Second" }
                    },
                    Tags = new string[] { "import", "active" }
                },
                new ImportSubscriber()
                {
                    Email = new EmailContact("third@mail.ru")
                    {
                        Status = ContactStatus.Active,
                        ExcludedListIds = new long[] { 2, 3 },
                        UnsubscribedListIds = new long[] { 10 }
                    },
                    Phone = new PhoneContact("79031234567")
                    {
                        Status = ContactStatus.Active,
                        ExcludedListIds = new long[] { 2, 3 },
                        UnsubscribedListIds = new long[] { 10 }
                    },
                    Custom = new Dictionary<string, string>()
                    {
                        { "Bonus", "33" }
                    }
                },
                new ImportSubscriber()
                {
                    Email = new EmailContact("test@mail.ru"),
                    Phone = new PhoneContact("79001234567"),
                    Delete = true
                }
            )
            {
                DoubleOptIn = true,
                OverwriteTags = true,
                OverwriteLists = true
            };
            args = import.Serialize();
        }

        [Fact]
        public void CheckFieldNames()
        {
            var names = (
                from item in args
                where item.Key.StartsWith("field_names")
                select (string)item.Value).ToArray();
            string[] expectedNames = new string[]
            {
                "delete",
                "tags",
                "email",
                "email_status",
                "email_availability",
                "email_add_time",
                "email_request_ip",
                "email_confirm_ip",
                "email_confirm_time",
                "email_list_ids",
                "email_subscribe_times",
                "email_unsubscribed_list_ids",
                "email_excluded_list_ids",
                "phone",
                "phone_status",
                "phone_availability",
                "phone_add_time",
                "phone_request_ip",
                "phone_list_ids",
                "phone_subscribe_times",
                "phone_unsubscribed_list_ids",
                "phone_excluded_list_ids",
                "Name",
                "Company",
                "Bonus"
            };
            Array.Sort(expectedNames);
            Array.Sort(names);
            Assert.Equal(expectedNames, names);
        }

        [Fact]
        public void CheckFieldNamesParameters()
        {
            var parameters = (
                from item in args
                where item.Key.StartsWith("field_names")
                select item.Key).Distinct().ToArray();
            Assert.Equal(25, parameters.Length);
            Assert.All(parameters, p => Assert.Matches(@"field_names\[\d+\]", p));
        }

        [Fact]
        public void TestData_Email()
        {
            var ind = (
                from item in args
                where item.Value == "email"
                select int.Parse(item.Key.Split('[')[1].TrimEnd(']'))).Single();
            string key;

            key = "data[0][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("first@mail.ru", args[key]);

            key = "data[2][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("third@mail.ru", args[key]);

            key = "data[3][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("test@mail.ru", args[key]);

            Assert.False(args.ContainsKey("data[1][" + ind + "]"));
        }

        [Fact]
        public void TestData_Phone()
        {
            var ind = (
                from item in args
                where "phone" == item.Value
                select int.Parse(item.Key.Split('[')[1].TrimEnd(']'))).Single();
            string key;

            key = "data[1][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("79021234567", args[key]);

            key = "data[2][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("79031234567", args[key]);

            key = "data[3][" + ind + "]";
            Assert.True(args.ContainsKey(key));
            Assert.Equal("79001234567", args[key]);

            Assert.False(args.ContainsKey("data[0][" + ind + "]"));
        }

        // TODO: test other fields and remove TestQuery()
        [Fact]
        public void TestQuery()
        {
            var actual = TestUtility.ParseQuery(new UniSenderRequest("tt", "action", "test", args).GetQuery());

            var expected = new Dictionary<string, string>()
            {
                { "format", "json" },
                { "api_key", "test" }
            };
            foreach (var item in args)
            {
                string value = null;
                if (item.Value is Array)
                    value = String.Join(",", (item.Value as Array)
                        .Cast<object>()
                        .Select(i => i.ToString()));
                else if (item.Value != null)
                    value = item.Value.ToString();
                if (!string.IsNullOrEmpty(value))
                    expected.Add(item.Key, value);
            }

            Assert.Equal(expected, actual);
        }
    }
}
